/*
PARI/GP scripts for genetic threads
=============================================================
File: GeneticThreads.txt    
Link: https://oeis.org/wiki/File:GeneticThreads.txt
Content: PARI/GP code
=============================================================
Note: The script GT_Trunc1 was originally named GT_DivMod0
and appears under that name in several OEIS sequences.
The following line guarantees backward compatibility:

GT_DivMod0(nmax,prop,b=10) = GT_Trunc1(nmax,prop,b);
 

Preliminary exploration version of "inheritance threads" for
a property P and an endomorphism E on a set S. By an
inheritance thread, in this context, is understood a chain of
elements s, E(s), E(E(s), ... which all share the property P.

The final goal of this study is to understand better the
interplay between an endomorphism on a set S and a property
of its elements (a subset of S) and see whether any general
rules might be deduced regarding the thread lengths
distributions, their bounds, etc.

A dedicated article is to follow.

So far, this is limited to sets S of naturals or non-negative
integers and the endomorhism E(n) = floor(n/b) = n\b which is
equvalent to truncation of the rightmost digit of n in base b.

Examples of use:

a) ---------- Primality-based properties
(See https://oeis.org/wiki/File:PrimesRelatedFunctions.txt):

GT_Trunc1(20000,isprime)
       generates A024770, A050986 and A127890.
GT_Trunc1(20000,isprime,16)
       generates A237600, A237601 and A237602       

GT_Trunc2(10000,IsReversiblePrime,10)
       generates A238850.
GT_Trunc2(100000,IsReversiblePrime,16)
       generates A238851.
GT_Trunc2(100000,IsReversiblePrime,100)
       generates A238852.
GT_Trunc2(100000,IsReversiblePrime,256)
       generates A238853.
GT_Trunc2(100000,IsReversiblePrime,256)
       generates A238853.

GT_Trunc1(20000,IsNotPrime)
       generates A202259.
GT_Trunc1(20000,IsMoebiusZero) 
       generates A237607 and A237608.

b) ---------- Digit-based properties
(see https://oeis.org/wiki/File:DigitBasedFunctions.txt):

GT_Trunc2(10000,RTruncIsCoprime,b) generates
       A250038 (b=16), A250040 (b=10), A250042 (b=9),
       A250044 (b= 8), A250046 (b= 7), A250048 (b=6),
       A250050 (b= 5), A250036 (b= 4), A250035 (b=3).
GT_Trunc2(10000,RTruncIsNotCoprime,b)
       A250039 (b=16), A250041 (b=10), A250043 (b=9),
       A250045 (b= 8), A250047 (b= 7), A250049 (b=6),
       A250051 (b= 5), A250037 (b= 4), A005823 (b=3).

Some of the above sequences are finite (the first two groups
in (a), others are infinite.
*/


GT_Trunc1(nmax,prop,b=10) =
/* ----------------------------------------------------------
Inheritance thread generator for a property P and the
endomorphism E(n)->n\b (last digit truncation in base-b).
The property function must be of the form BOOL prop(n).

It searches for all numbers n which have the property P and
all of whose successors E(E(...E(n)...)), short of the
terminating zero, have it as well. Evidently, if n belongs
to the set and E(n)>0, then so does also E(n).

The property P is defined by the boolean prop(n) function
which must return either false (0) or true (non-zero).

The function returns an array with <=nmax numbers having
the specified property and maintaining it when their b-base
expansion is truncated on the right by one or more digits.

The returned vector is sorted by value. When there are less
entries than nmax, the size of the returned vector equals
the actual number. If no number matches the conditions,
the message "No solution" is printed.

The function also prints how many entries there are for
d significant digits, d = 1,2,.., and what is the largest
one for each d.

Considering that there is no end to properties of numbers,
this is an inexhaustible source of integer sequences,
some finite, and some only presumably so (I do not see
any theoretical tool right now to ascertain whether one
of these sequences terminates, other than actually
hitting 0 at some point.

Programming reminders:
  v   ... vector of integers having the property prop
  n   ... last used index in v
  g   ... generation index (equals number of "digits") 
  lgs ... index where the last generation starts
  lge ... index where the last generation ends
  c   ... count for current generation
  an  ... element under test
---------------------------------------------------------- */
{
  my (n=0,v=vector(nmax),g=1,lgs=1,lge,an,c);
  for (k=1,b-1,if (prop(k),v[n++]=k));
  lge=n; c=lge-lgs+1;
  while (c, print(g," ",c," ",v[lge]); g++;
    for (k=lgs,lge,
      for (m=0,b-1, an=b*v[k]+m;
        if (prop(an), v[n++]=an;if (n>=nmax,return (v)));
      ); 
    );
    lgs=lge+1; lge=n; c=lge-lgs+1;
  );
  if (n, return (v[1..n]));
  print("No solution");
}


GT_Trunc2(nmax,prop,b=10) =
/* ----------------------------------------------------------
This is almost the same as above, except that the property
function prop takes two arguments, the second one of which
is the base. It must be of the form BOOL prop(n,b).
---------------------------------------------------------- */
{
  my (n=0,v=vector(nmax),g=1,lgs=1,lge,an,c);
  for (k=1,b-1,if (prop(k,b),v[n++]=k));
  lge=n; c=lge-lgs+1;
  while (c, print(g," ",c," ",v[lge]); g++;
    for (k=lgs,lge,
      for (m=0,b-1, an=b*v[k]+m;
        if (prop(an,b), v[n++]=an;if (n>=nmax,return (v)));
      ); 
    );
    lgs=lge+1; lge=n; c=lge-lgs+1;
  );
  if (n, return (v[1..n]));
  print("No solution");
}


GT_Trunc3(bmin,bmax,prop,ofile) =
/* ----------------------------------------------------------
Like GT_Trunc2 but cycles over all bases b = bmin..bmax and,
for each b, stores the in the specified output text file:
1) the base value b,
2) counts of instances for 1,2,3,... digits, until 0 is hit,
3) total count,
4) maximum number of digits,
5) largest number.

The assumption is that for each base, there exists a maximum
number with the sought property, otherwise the program will
hang. While the calculation progresses, the determined values
for each base are printed.

The returned file must be analyzed and "filtered" to
extract the individual sequences published in OEIS.

Using nmax = 500000; the procedure stops at base 351 for
lack of stack RAM. Going beyond would be anyway extremely
time consuming (many days of PC CPU time).

Examples of use:

GT_Trunc3(2,350,IsReversiblePrime,"ofile.txt")
  generates data for A238854, A238855, A238856, A238857.

For bmin=2,bmax=4, the outfile contents look like this:
[2,0,1,0,0 ,3,1,1,1,0,3,3,23 ,4,2,1,1,0,4,3,53, ...]

One can read the file in GP by
  \r outfile.txt
and use ad-hoc scripts to extract the individual items.
---------------------------------------------------------- */
{
  my (nmax=100000,n,v,g,lgs,lge,an,c);
  write1(ofile,"[");
  for (b=bmin,bmax, print1(b,", ");
    if (b>bmin,write1(ofile,",")); 
    write1(ofile,b,",");
    v=vector(nmax); n=0;
    for (k=1,b-1,if (prop(k,b),v[n++]=k));
    g=1; lgs=1; lge=n; c=(lge-lgs+1);
    while (c, print1(c,", "); write1(ofile,c,",");g++;
      for (k=lgs,lge,
        for (m=0,b-1, an=b*v[k]+m;
          if (prop(an,b), v[n++]=an;if (n>=nmax, break));
        );if (n>=nmax, break);
      );if (n>=nmax, break);
      lgs=lge+1; lge=n; c=lge-lgs+1;
    );
    if (n>=nmax,write(ofile," abandoned");break);
    if (n==0,n++);
    print(0,", ",n,", ",g-1,", ",v[n]);
    write1(ofile,0,",",n,",",g-1,",",v[n]);
  );
  write(ofile,"]");
}

/*
=============================================================
   Contributed to OEIS Wiki by Stanislav Sykora
=============================================================
*/
